iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
Modern Web

從 0 到 1:30 篇文章帶你玩轉 Electron 與 React系列 第 8

多視窗應用的實作與視窗管理 (理論篇)

  • 分享至 

  • xImage
  •  

Electron 作為一個桌面應用框架,提供了非常靈活的視窗管理功能,可以讓開發者輕鬆實現多視窗應用。

無論是獨立的子視窗、彈出窗口,還是互相通信的多視窗程式,Electron 都可以透過其豐富的 API 實現。

在這篇文章中,筆者將介紹如何在 Electron 程式中實現多視窗程式,並探討視窗之間的通信和管理技巧,讓讀者可以透過這些技巧實作出多視窗的應用程式。

為什麼需要多視窗程式?

在桌面程式開發中,多視窗的場景經常出現,例如:

  • 獨立視窗:使用者需要打開一個新的窗口來顯示詳細資訊或設定介面,與主視窗獨立運行。
  • 子視窗:主視窗需要控制多個子視窗,例如彈出視窗、modal 或簡單的小菜單。
  • 多任務處理:使用者可能同時處理多個視窗,每個視窗負責不同的任務。

多視窗的架構允許程式以更加靈活的方式運行,提升使用者體驗,尤其在需要展示大量資訊或進行多任務操作時。

實作步驟:如何在 Electron 中實現多視窗應用

1. 創建多個視窗

在 Electron 中,視窗是由 BrowserWindow 類創建的。

要實現多視窗程式,我們只需創建多個 BrowserWindow 物件,並載入不同的內容。

const { app, BrowserWindow } = require('electron');
let mainWindow, secondaryWindow;

function createMainWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      contextIsolation: true,
      nodeIntegration: false,
    },
  });

  mainWindow.loadFile('index.html'); // 載入主視窗的 HTML
}

function createSecondaryWindow() {
  secondaryWindow = new BrowserWindow({
    width: 600,
    height: 400,
    parent: mainWindow,  // 將此視窗設定為主視窗的子視窗
    webPreferences: {
      contextIsolation: true,
      nodeIntegration: false,
    },
  });

  secondaryWindow.loadFile('secondary.html'); // 載入子視窗的 HTML
}

app.whenReady().then(() => {
  createMainWindow();
  createSecondaryWindow();

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  secondaryWindow.on('closed', () => {
    secondaryWindow = null;
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

在這個範例中,我們創建了兩個視窗:

  1. 主視窗
  2. 子視窗

mainWindow 是主程式視窗,而 secondaryWindow 是子視窗。每個視窗都可以載入不同的 HTML 文件,顯示不同的內容。

2. 視窗之間的通信

當有多個視窗時,視窗之間的通信就變得至關重要。

Electron 提供了兩種主要的通信方式:

  • IPC(Inter-Process Communication,程序之間通信):使用 ipcMain 和 ipcRenderer 來在主程序與渲染程序之間進行通信。
  • Electron 的 webContents API:用來讓不同視窗之間進行直接的通信。

IPC 通信

IPC 是最常用的通信方式,特別是在不同的視窗需要與主程序通信時。

以下是一個簡單的範例,展示如何讓子視窗向主視窗發送訊息,並接收主視窗的回覆:

主程序 (main.js):
import { ipcMain } from 'electron'


ipcMain.on('message-from-secondary', (event, message) => {
  console.log('收到來自子視窗的訊息:', message);
});
子視窗 (secondary.js):
import { ipcRenderer } from 'electron'

// 向主程序發送訊息
ipcRenderer.send('message-from-secondary', '你好,這是子視窗');

在這個例子中,子視窗可以向主程序發送訊息,並可以繼續執行後面想要進行的行為,例如調整視窗大小。

使用 webContents API 進行視窗通信

如果想要讓不同的視窗之間直接通信,可以使用 Electron 提供的 webContents API。

每個視窗都有自己的 webContents 物件,可以通過它來向其他視窗發送訊息。

主程序 (main.js):
// 主視窗接收訊息
mainWindow.webContents.on('message', (event, message) => {
  console.log('收到子視窗的訊息:', message);
});
子視窗 (secondary.js):
// 子視窗發送訊息息給主視窗
secondaryWindow.webContents.send('message', '來自子視窗的訊息');

這種方式允許你在不通過主程序的情況下,讓多個視窗直接進行通信。

IPC & webContents API 混合使用通信

以下呈現兩種方法的混合用法

主程序 (main.js):
import { ipcMain } from 'electron'


ipcMain.on('message-from-secondary', (event, message) => {
  console.log('收到來自子視窗的訊息:', message);
  
  // 可以向所有視窗廣播訊息
  mainWindow.webContents.send('message-from-main', '這是來自主視窗的回覆');
});
子視窗 (secondary.js):
import { ipcRenderer } from 'electron'

// 向主程序發送訊息
ipcRenderer.send('message-from-secondary', '你好,這是子視窗');

// 接收來自主視窗的訊息
ipcRenderer.on('message-from-main', (event, message) => {
  console.log('收到主視窗的訊息:', message);
});

在這個例子中,子視窗可以向主程序發送訊息,主程序可以接收到訊息並向主視窗和其他視窗回覆。

3. 視窗的管理與生命周期控制

在多視窗應用中,如何管理視窗的打開、關閉以及生命周期是非常重要的。以下是一些視窗管理的最佳實踐:

父子視窗關係

在某些應用場景下,子視窗應該與主視窗保持關聯。

當主視窗被關閉時,子視窗應該自動關閉,這可以通過 parent 屬性來設置父子視窗關係。

let childWindow = new BrowserWindow({
  parent: mainWindow,  // 設置為主視窗的子視窗
  modal: true,         // 設置為 modal,會鎖住主視窗
  show: false          // 可以在載入完成後再顯示
});

當設置了 modal 時,子視窗將作為 modal,使用者無法與主視窗互動,直到子視窗被關閉。

視窗打開與關閉的控制

視窗的打開與關閉應該是靈活的,並且要根據需求動態管理視窗狀態。

以下是一些打開和關閉視窗的方式:

動態創建與打開視窗
let secondaryWindow = null;

function createSecondaryWindow() {
  if (!secondaryWindow) {
    secondaryWindow = new BrowserWindow({
      width: 600,
      height: 400,
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
      },
    });

    secondaryWindow.loadFile('secondary.html'); // 載入子視窗內容

    secondaryWindow.on('close', () => {
      secondaryWindow = null; // 清除引用,允許垃圾回收
    });
  }
}
銷毀視窗

在某些情況下,你可能需要強制銷毀一個視窗,例如在應用退出時或不再需要子視窗時。

if (secondaryWindow) {
  secondaryWindow.destroy(); // 強制銷毀視窗
  secondaryWindow = null;
}
動態關閉視窗
function closeSecondaryWindow(window) {
  if (secondaryWindow && !secondaryWindow.isDestroyed()) {
    secondaryWindow.close();  // 關閉視窗
  }
}
顯示與隱藏視窗

在某些情況下,你可能不需要關閉視窗,而是將其隱藏起來,稍後再顯示。

這在某些持續性的應用場景(如工具窗口)中特別有用。

隱藏視窗

secondaryWindow.hide();  // 隱藏視窗

顯示視窗

secondaryWindow.show();  // 顯示已隱藏的視窗

這些方法允許你靈活地控制視窗的打開與關閉,或是顯示及隱藏,並且在需要時釋放資源。

總結

在 Electron 中實現多視窗程式不僅可以擴展程式的功能,還能提升用戶的操作體驗。

通過創建多個 BrowserWindow 視窗、使用 IPCwebContents 進行視窗間的通信,你可以構建出功能豐富且靈活的桌面程式。

視窗管理在多視窗應用中扮演了關鍵角色,應用中需要根據具體場景控制視窗的打開、關閉和生命周期。藉助 Electron 的強大 API,你可以輕鬆地實現各種視窗需求,打造多任務、跨螢幕操作的桌面程式(後面的章節會有更多的實例喔,可持續關注~)。

下一篇,我們會將上一篇文章:React 與 Electron 的整合:打造動態的用戶界面 所提到的 桌面計時器 增加多視窗的功能,來示範這篇文章所提到的內容~


上一篇
React 與 Electron 的整合:打造動態的用戶界面
下一篇
視窗 API 大集合
系列文
從 0 到 1:30 篇文章帶你玩轉 Electron 與 React30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言